package summary

import (
	"EasyCollect/global"
	"fmt"
	log "code.google.com/p/log4go"
	"EasyCollect/sqls"
	"EasyCollect/util"
	"errors"
	"EasyCollect/express_parser"
	"strings"
)
const(
	where="where"
	whereUpper="WHERE"
	shardingStr=" where %s=%v and "
)
/**
	非分片的任务，构建查询sql语句
	优先执行src-query ,如果没配置，则会根据 src-condition，src-paramete，src-table构建
 */
func querySqlBuildNoSharding(task *global.Task) (sqlStr string,params []interface{}) {

	if task.SrcQuery!="" {
		return task.SrcQuery,make([]interface{},0)
	}
	parameters := sqls.ParametersConvert(task.SrcParameter)
	sql :=fmt.Sprintf("select * from %s where %s",
		task.SrcTable, task.SrcCondition)

	if task.SrcLimit>0 {
		sql = fmt.Sprintf("%s limit %v",sql,task.SrcLimit)
	}
	return sql,parameters
}

/**
	构建删除src-table的数据的sql语句
 */
func buildDeleteSql(taskCfg *global.Task, result map[string]interface{}) string {
	sqlStr:= fmt.Sprintf("delete from %s where %s=%v",taskCfg.SrcTable,taskCfg.SrcKey,result[taskCfg.SrcKey])
	return sqlStr
}

/**
	构建insert target-table的sql语句。
 */
func buildInsertSql(taskCfg *global.Task, result map[string]interface{}) (SqlStr string,params []interface{}) {

	if len(taskCfg.TargetColumnMapping)==0 {
		return buildInsertSqlByDefaultColumn(taskCfg,result)
	}else{
		return buildInsertSqlByMappingColumn(taskCfg,result)
	}
}
/**
	如果没有配置target-column-mapping，会认为src-table和target-table的表结构的字段列一致，执行默认的构造sql方法
 */
func buildInsertSqlByDefaultColumn(taskCfg *global.Task, result map[string]interface{}) (SqlStr string,params []interface{}) {
	//保存数据的副本
	data := make(map[string]interface{})
	//如果配置了要排除的列，列转小写
	excludeCols := make(map[string]string,0)
	for k,v := range taskCfg.ExcludeColumn {
		excludeCols[util.ToLowerCase(k)]=v
	}
	for k,v:= range result{
		if _,ok := excludeCols[util.ToLowerCase(k)]; !ok {
			data[k]=v
		}
	}
	if len(data)==0 {
		errStr :=fmt.Sprintf("insert params size must >0,your : [%s],please check your excludeColumn config ",data)
		log.Error(errStr)
		global.PanicError(errors.New(errStr),taskCfg)
	}

	//列，逗号隔开
	columnStr:=""
	//值占位符，多个问号
	valuePlaceholder:=""
	//值列表
	params = make([]interface{},0)

	for k,v := range data {
		columnStr=columnStr+k+","
		valuePlaceholder=valuePlaceholder+"?,"
		params=append(params,v)
	}
	columnStr=columnStr[0:len(columnStr)-1]
	valuePlaceholder=valuePlaceholder[0:len(valuePlaceholder)-1]

	sqlStr := fmt.Sprintf("insert into %s(%s) values(%s)",
		taskCfg.TargetTable,columnStr,valuePlaceholder)

	return sqlStr,params
}

/**
	如果配置了target-column-mapping，会认为src-table和target-table的表结构可能异构。或者只是数据搜集，插入到一个新表
 */
func buildInsertSqlByMappingColumn(taskCfg *global.Task, result map[string]interface{}) (SqlStr string,params []interface{}) {

	//将数据的每一个列先转小写
	data := make(map[string]interface{})
	for k,v := range result{
		data[util.ToLowerCase(k)]=v
	}

	//列，逗号隔开
	columnStr:=""
	//值占位符，多个问号
	valuePlaceholder:=""
	//值列表
	params = make([]interface{},0)
	for k,v := range taskCfg.TargetColumnMapping {
		columnStr=columnStr+k+","
		valuePlaceholder=valuePlaceholder+"?,"

		express :=v
		if strings.Contains(v,"${") {
			express = util.ToLowerCase(v)
		}
		cell :=  express_parser.ParserScript(express)
		//如果express 包含${ 代表它是一个列的占位符，去data里面找到对应的数据，否则，则是时间表达式或者原样输出的值。
		if strings.Contains(express,"${"){
			params=append(params,data[util.ToLowerCase(cell)])
		}else{
			params=append(params,cell)
		}
	}
	columnStr=columnStr[0:len(columnStr)-1]
	valuePlaceholder=valuePlaceholder[0:len(valuePlaceholder)-1]

	sqlStr := fmt.Sprintf("insert into %s(%s) values(%s)",
		taskCfg.TargetTable,columnStr,valuePlaceholder)

	return sqlStr,params
}

/**
	构建update target-table的sql语句。
 */
func buildUpdateSql(taskCfg *global.Task, result map[string]interface{}) (SqlStr string,params []interface{}) {

	//将数据的每一个列先转小写
	data := make(map[string]interface{})
	for k,v := range result{
		data[util.ToLowerCase(k)]=v
	}

	//列，逗号隔开
	columnStr:=""
	//条件，逗号隔开
	conditionStr:=""
	//值列表
	params = make([]interface{},0)
	for k,v := range taskCfg.TargetColumnMapping {
		columnStr=columnStr+k+"=?,"

		express :=v
		if strings.Contains(v,"${") {
			express = util.ToLowerCase(v)
		}
		cell :=  express_parser.ParserScript(express)
		//如果express 包含${ 代表它是一个列的占位符，去data里面找到对应的数据，否则，则是时间表达式或者原样输出的值。
		if strings.Contains(express,"${"){
			params=append(params,data[util.ToLowerCase(cell)])
		}else{
			params=append(params,cell)
		}
	}
	for k,v := range taskCfg.TargetUpdateCondition {
		conditionStr=conditionStr+k+"=? and "

		express :=v
		if strings.Contains(v,"${") {
			express = util.ToLowerCase(v)
		}
		cell :=  express_parser.ParserScript(express)
		//如果express 包含${ 代表它是一个列的占位符，去data里面找到对应的数据，否则，则是时间表达式或者原样输出的值。
		if strings.Contains(express,"${"){
			params=append(params,data[util.ToLowerCase(cell)])
		}else{
			params=append(params,cell)
		}
	}
	columnStr=columnStr[0:len(columnStr)-1]
	conditionStr=conditionStr[0:len(conditionStr)-4]
	sqlStr := fmt.Sprintf("update %s set %s where %s",
		taskCfg.TargetTable,columnStr,conditionStr)

	return sqlStr,params
}

/**
	为构建的sql添加分片项,直接截取where 后面，进行拼接
 */
func addShardingForSql(sqlStr string, sharding int,shardingColumn string) string {
	if strings.Contains(sqlStr,where) {
		sqlParts	 := strings.Split(sqlStr,where)
		shardingStr := fmt.Sprintf(shardingStr,shardingColumn,sharding)
		return sqlParts[0]+shardingStr+sqlParts[1]
	}
	if strings.Contains(sqlStr,whereUpper){
		sqlParts	 := strings.Split(sqlStr,whereUpper)
		shardingStr := fmt.Sprintf(shardingStr,shardingColumn,sharding)
		return sqlParts[0]+shardingStr+sqlParts[1]
	}
	return sqlStr
}